
#include "FunctionChart.h"
#include <math.h>


FunctionChart::FunctionChart(int dim, double **limits, int num_slices) : Chart(dim, limits, num_slices)
{
}


FunctionChart::~FunctionChart()
{
}


void
FunctionChart::_store_function(double (*function) (double *data, void *additional_data), void *additional_data)
{
	_functions.push_back(function);
	_extra_data.push_back(additional_data);
}


void
FunctionChart::_add_function_field()
{
	vtkSmartPointer<vtkFloatArray> function_column = vtkSmartPointer<vtkFloatArray>::New();

	// TODO: deallocate it in the end!
	char* name = (char*) (calloc(32, sizeof(char)));
	sprintf(name, "Function %d", (int) _functions.size());
	function_column->SetName(name);

	_table->AddColumn(function_column);
}


void
FunctionChart::AddFunction(double (*function) (double *data, void *additional_data), void *additional_data)
{
	_add_function_field();
	_store_function(function, additional_data);
}



vtkSmartPointer<vtkChartXY>
FunctionChart::BuildChart()
{
	int i, j, k, l;
	double *data = (double *) calloc (_dim, sizeof(double));

	// ***********************************************
	// NOTE: I don't know yet why, but I must set the
	// number of rows after adding all of the columns.
	// It's not cool because all the hard work became
	// centralized here. And it makes this method
	// really expensive.
	// ***********************************************
	_table->SetNumberOfRows(_num_rows);

	vtkSmartPointer<vtkChartXY> chart = vtkSmartPointer<vtkChartXY>::New();

	// fill the domains axis and initialize the data
	for (i = 0; i < _dim; i++)
	{
		for (j = 0; j < _num_rows; j++)
			_table->SetValue(j, i, _limits[i][0] + j * _increments[i]);

		data[i] = _limits[i][0];
	}

	// fill the function fields
	for (k = 0; k < _functions.size(); k++)
	{
		for (j = 0; j < _num_rows; j++)
		{
			for (i = 0; i < _dim; i++)
				data[i] += _increments[i];

			// TODO: it's not ready to work in 3D yet!
			_table->SetValue(j, _dim + k, _functions[k](data, _extra_data[k]));
		}

		vtkPlot *line = chart->AddPlot(vtkChart::LINE);

#if VTK_MAJOR_VERSION <= 5
		line->SetInput(_table, 0, _dim + k);
#else
		line->SetInputData(_table, 0, _dim + k);
#endif
		line->SetColor(0, 255, 0, 255);
		line->SetWidth(1.0);
	}

	free(data);
	return chart;
}
